/* Classic Ladder Project */
/* Copyright (C) 2001-2012 Marc Le Douarain */
/* http://membres.lycos.fr/mavati/classicladder/ */
/* http://www.sourceforge.net/projects/classicladder */
/* October 2011 */
/* ------------------------------------- */
/* Monitor connect window (IP or serial) */
/* + frames monitor window               */
/* ------------------------------------- */
/* This library is free software; you can redistribute it and/or */
/* modify it under the terms of the GNU Lesser General Public */
/* License as published by the Free Software Foundation; either */
/* version 2.1 of the License, or (at your option) any later version. */

/* This library is distributed in the hope that it will be useful, */
/* but WITHOUT ANY WARRANTY; without even the implied warranty of */
/* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU */
/* Lesser General Public License for more details. */

/* You should have received a copy of the GNU Lesser General Public */
/* License along with this library; if not, write to the Free Software */
/* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA */

#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#include <gtk/gtk.h>

#include "classicladder.h"
#include "global.h"
#include "menu_and_toolbar_gtk.h"
#include "preferences.h"
#include "classicladder_gtk.h"
#include "monitor_windows_gtk.h"

/* for connect window */
static GtkWidget* pDialogBox;
static GtkWidget * pRadioModeChoice[ 2 ];
static GtkWidget * pEntryIP;
static GtkWidget * pEntrySerial,*pEntrySerialSpeed;

/* for monitor window */
GtkWidget *MonitorWindow;
GtkWidget *MonitorFramesView;
GtkWidget *MonitorAutoScroll;
GtkWidget *MonitorManualFrameEntry;

void SetSensitivesDependingMode( void )
{
	char bIpMode = gtk_toggle_button_get_active( GTK_TOGGLE_BUTTON(pRadioModeChoice[0]) );
	gtk_widget_set_sensitive( pEntryIP, bIpMode );
	gtk_widget_set_sensitive( pEntrySerial, !bIpMode );
	gtk_widget_set_sensitive( pEntrySerialSpeed, !bIpMode );
}

void RadioModeChoiceToggledClick (GtkToggleButton *togglebutton, gpointer user_data)
{
	SetSensitivesDependingMode( );
}

/* to simulate "OK" click when return done on IP address / Serial port/speed */
void DialogConnectDoResponseOk( void )
{
	gtk_dialog_response( GTK_DIALOG(pDialogBox), GTK_RESPONSE_OK );
}

char OpenDialogMonitorConnect( void )
{
	GtkWidget * hbox[ 3 ];
	GtkWidget * pLabel;
	char Buff[ 30 ];

	char OkDone = FALSE;

	if ( InfosGUI->TargetMonitor.RemoteConnected || InfosGUI->TargetMonitor.RemoteFileTransfer )
	{
		ShowMessageBox("Error", "Already in communication with the remote target (monitor or file transfer)...","Ok");
		return OkDone;
	}

	pDialogBox = gtk_dialog_new_with_buttons( InfosGUI->TargetMonitor.TransferFileNum==-1?"Target to connect":"File transfer",
		GTK_WINDOW( MainSectionWindow ),
		GTK_DIALOG_MODAL,
		GTK_STOCK_OK,GTK_RESPONSE_OK,
		GTK_STOCK_CANCEL,GTK_RESPONSE_CANCEL,
		NULL);
	
	hbox[0] = gtk_hbox_new (FALSE, 0);
	gtk_container_add (GTK_CONTAINER(GTK_DIALOG(pDialogBox)->vbox), hbox[0]);
	pRadioModeChoice[0] = gtk_radio_button_new_with_label( NULL, "IP network" );
			gtk_signal_connect(GTK_OBJECT (pRadioModeChoice[0]), "toggled",
					(GtkSignalFunc) RadioModeChoiceToggledClick, (void*)NULL);
	gtk_box_pack_start(GTK_BOX(hbox[0]), pRadioModeChoice[0], TRUE, TRUE, 0);
	pRadioModeChoice[1] = gtk_radio_button_new_with_label_from_widget (GTK_RADIO_BUTTON (pRadioModeChoice[0]), "Serial link");
	gtk_box_pack_start(GTK_BOX(hbox[0]), pRadioModeChoice[1], TRUE, TRUE, 0);

	hbox[1] = gtk_hbox_new (FALSE, 0);
	gtk_container_add (GTK_CONTAINER(GTK_DIALOG(pDialogBox)->vbox), hbox[1]);
	pLabel = gtk_label_new( "IP address or hostname" );
	gtk_box_pack_start(GTK_BOX(hbox[1]), pLabel, FALSE, FALSE, 0);
	pEntryIP = gtk_entry_new();
	gtk_entry_set_text( GTK_ENTRY(pEntryIP), InfosGUI->TargetMonitor.RemoteAdrIP );
	gtk_box_pack_start(GTK_BOX(hbox[1]), pEntryIP, FALSE, FALSE, 0);
	gtk_signal_connect(GTK_OBJECT(pEntryIP), "activate",
				(GtkSignalFunc)DialogConnectDoResponseOk, 0);

	hbox[2] = gtk_hbox_new (FALSE, 0);
	gtk_container_add (GTK_CONTAINER(GTK_DIALOG(pDialogBox)->vbox), hbox[2]);
	pLabel = gtk_label_new( "Serial port" );
	gtk_box_pack_start(GTK_BOX(hbox[2]), pLabel, FALSE, FALSE, 0);
	pEntrySerial = gtk_entry_new();
	gtk_entry_set_text( GTK_ENTRY(pEntrySerial), InfosGUI->TargetMonitor.RemoteWithSerialPort );
	gtk_box_pack_start(GTK_BOX(hbox[2]), pEntrySerial, FALSE, FALSE, 0);
	gtk_signal_connect(GTK_OBJECT(pEntrySerial), "activate",
				(GtkSignalFunc)DialogConnectDoResponseOk, 0);
	pLabel = gtk_label_new( "Speed" );
	gtk_box_pack_start(GTK_BOX(hbox[2]), pLabel, FALSE, FALSE, 0);
	pEntrySerialSpeed = gtk_entry_new();
	sprintf( Buff, "%d", InfosGUI->TargetMonitor.RemoteWithSerialSpeed );
	gtk_entry_set_text( GTK_ENTRY(pEntrySerialSpeed), Buff );
	gtk_box_pack_start(GTK_BOX(hbox[2]), pEntrySerialSpeed, FALSE, FALSE, 0);
	gtk_signal_connect(GTK_OBJECT(pEntrySerialSpeed), "activate",
				(GtkSignalFunc)DialogConnectDoResponseOk, 0);

	if ( InfosGUI->TargetMonitor.RemoteWithSerialPort[0]!='\0' )
	{
		gtk_toggle_button_set_active( GTK_TOGGLE_BUTTON(pRadioModeChoice[1]), TRUE );
		gtk_widget_grab_focus( pEntrySerial );
	}
	else
	{
		gtk_widget_grab_focus( pEntryIP );
	}
	SetSensitivesDependingMode( );
	gtk_widget_show_all(GTK_DIALOG(pDialogBox)->vbox);

	switch (gtk_dialog_run(GTK_DIALOG(pDialogBox)))
	{
		case GTK_RESPONSE_OK:
		{
			char bIpMode = gtk_toggle_button_get_active( GTK_TOGGLE_BUTTON(pRadioModeChoice[0]) );
			if ( bIpMode )
			{
				strcpy( InfosGUI->TargetMonitor.RemoteAdrIP, gtk_entry_get_text(GTK_ENTRY(pEntryIP) ) );
				InfosGUI->TargetMonitor.RemoteWithSerialPort[ 0 ] = '\0';
			}
			else
			{
				InfosGUI->TargetMonitor.RemoteAdrIP[ 0 ] = '\0';
				strcpy( InfosGUI->TargetMonitor.RemoteWithSerialPort, gtk_entry_get_text(GTK_ENTRY(pEntrySerial) ) );
				InfosGUI->TargetMonitor.RemoteWithSerialSpeed = atoi( gtk_entry_get_text(GTK_ENTRY(pEntrySerialSpeed) ) );
			}
			OkDone = TRUE;
			break;
		}
	}

	gtk_widget_destroy(pDialogBox);
	return OkDone;
}

void ButtonCleanUpSignal( )
{
	GtkTextBuffer *buffer;
        /* get the text buffer */
	buffer = gtk_text_view_get_buffer( GTK_TEXT_VIEW( MonitorFramesView ) );
	gtk_text_buffer_set_text (buffer, "", -1);
}
static gint MonitorManualFrameEntrySignal(GtkWidget *widget, int NumVarSpy)
{
	int StrLgt = strlen( gtk_entry_get_text( GTK_ENTRY(MonitorManualFrameEntry) ) );
	if ( StrLgt>0 )
	{
		char * StrAllocated = malloc( StrLgt+1 );
		if ( StrAllocated!=NULL )
		{
			strcpy( StrAllocated, gtk_entry_get_text( GTK_ENTRY(MonitorManualFrameEntry) ) );
			InfosGUI->TargetMonitor.AskTargetForThisManualFrame = StrAllocated;
		}
	}
	return TRUE;
}
gint MonitorWindowDeleteEvent( GtkWidget * widget, GdkEvent * event, gpointer data )
{
// Here, we must only toggle the menu check that will call itself the function below to close the window ...
//	gtk_widget_hide( MonitorWindow );
	SetToggleMenuForMonitorWindow( FALSE/*OpenedWin*/ );
	// we do not want that the window be destroyed.
	return TRUE;
}

// called per toggle action menu, or at startup (if window saved open or not)...
void OpenMonitorWindow( GtkAction * ActionOpen, gboolean OpenIt )
{
	if ( ActionOpen!=NULL )
		OpenIt = gtk_toggle_action_get_active( GTK_TOGGLE_ACTION(ActionOpen) );
	if ( OpenIt )
	{
		RestoreWindowPosiPrefs( "Monitor", MonitorWindow );
		gtk_widget_show( MonitorWindow );
		gtk_window_present( GTK_WINDOW(MonitorWindow) );
	}
	else
	{
		RememberWindowPosiPrefs( "Monitor", MonitorWindow, TRUE/*SaveWindowSize*/ );
		gtk_widget_hide( MonitorWindow );
	}
}
void RememberMonitorWindowPrefs( void )
{
	char WindowIsOpened = GTK_WIDGET_VISIBLE( GTK_WINDOW(MonitorWindow) );
	RememberWindowOpenPrefs( "Monitor", WindowIsOpened );
	if ( WindowIsOpened )
		RememberWindowPosiPrefs( "Monitor", MonitorWindow, TRUE/*SaveWindowSize*/ );
}
void MonitorWindowInitGtk()
{
	GtkWidget *vbox,*hbox;
	GtkWidget *ScrollWin,*ButtonCleanUp;
	MonitorWindow = gtk_window_new (GTK_WINDOW_TOPLEVEL);
	gtk_window_set_title ((GtkWindow *)MonitorWindow, "Master monitor frames with target");
	gtk_window_set_default_size(GTK_WINDOW(MonitorWindow), 400, 200);
	gtk_signal_connect( GTK_OBJECT( MonitorWindow ), "delete_event",
		(GtkSignalFunc)MonitorWindowDeleteEvent, 0 );

	vbox = gtk_vbox_new (FALSE, 0);
	gtk_container_add(GTK_CONTAINER(MonitorWindow),vbox);
	gtk_widget_show (vbox);

	/* Create a Scrolled Window that will contain the GtkTextView */
	ScrollWin = gtk_scrolled_window_new (NULL, NULL);
	gtk_box_pack_start(GTK_BOX(vbox), ScrollWin, TRUE, TRUE, 5);
	gtk_widget_show (ScrollWin);

	MonitorFramesView = gtk_text_view_new ();
	gtk_container_add(GTK_CONTAINER(ScrollWin),MonitorFramesView);
	gtk_scrolled_window_set_policy(GTK_SCROLLED_WINDOW(ScrollWin), GTK_POLICY_AUTOMATIC, GTK_POLICY_AUTOMATIC);
	gtk_widget_set_sensitive( MonitorFramesView, FALSE );
	gtk_widget_show( MonitorFramesView );

	hbox = gtk_hbox_new (FALSE, 0);
	gtk_box_pack_start (GTK_BOX(vbox), hbox, FALSE, FALSE, 0);
	gtk_widget_show (hbox);
	MonitorAutoScroll = gtk_check_button_new_with_label("Scroll");
	gtk_toggle_button_set_active( GTK_TOGGLE_BUTTON( MonitorAutoScroll ), TRUE );
	gtk_box_pack_start (GTK_BOX(hbox), MonitorAutoScroll, FALSE, FALSE, 0);
	gtk_widget_show (MonitorAutoScroll);
	ButtonCleanUp = gtk_button_new_with_label("CleanUp");
	gtk_box_pack_start(GTK_BOX(hbox),ButtonCleanUp,FALSE,FALSE,0);
	gtk_signal_connect(GTK_OBJECT (ButtonCleanUp), "clicked", 
			(GtkSignalFunc) ButtonCleanUpSignal, 0);
	gtk_widget_show( ButtonCleanUp );
	MonitorManualFrameEntry = gtk_entry_new( );
	gtk_box_pack_start(GTK_BOX(hbox),MonitorManualFrameEntry,FALSE,FALSE,0);
	gtk_signal_connect(GTK_OBJECT (MonitorManualFrameEntry), "activate", 
			(GtkSignalFunc) MonitorManualFrameEntrySignal, 0);
	gtk_widget_show( MonitorManualFrameEntry );
}


// do not call this function directly, use MonitorWindowAddText() ! */
// called with g_idle_add() which do not have the main GTK+ lock,
// so gdk_threads_enter() & gdk_threads_leave() functions required...
gboolean MonitorWindowAddTextFromMainGtk( gpointer text )
{
	GtkTextBuffer *buffer;
	GtkTextIter iter;
	GtkTextMark *mark;

	char * TextToFreeAfterUse = (char *)text;
gdk_threads_enter();

	if ( GTK_WIDGET_VISIBLE( GTK_WINDOW(MonitorWindow) ) )
	{

#ifdef AAAAAAAAA
	/* Get the text buffer */
	buffer = gtk_text_view_get_buffer( GTK_TEXT_VIEW( MonitorFramesView ) );
	/* Get end iter */
	gtk_text_buffer_get_end_iter( buffer, &iter );
	/* Add the message to the text buffer */
	gtk_text_buffer_insert( buffer, &iter, text, -1 );
	/* Scroll to end iter */
	gtk_text_view_scroll_to_iter( GTK_TEXT_VIEW (MonitorFramesView),
									&iter, 0.0, FALSE, 0, 0 );
#endif
	/* Returns the GtkTextBuffer being displayed by this text view. */
	buffer = gtk_text_view_get_buffer( GTK_TEXT_VIEW(MonitorFramesView) );
	/* Returns the mark that represents the cursor (insertion point). */
	mark = gtk_text_buffer_get_insert( buffer );
	/* Initializes iter with the current position of mark. */
	gtk_text_buffer_get_iter_at_mark( buffer, &iter, mark );
	/* Inserts buffer at position iter. */
	gtk_text_buffer_insert( buffer, &iter, TextToFreeAfterUse, -1 );
	/* Scrolls text_view the minimum distance such that mark is contained within the visible area of the widget. */
	if ( gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON( MonitorAutoScroll ) ) )
		gtk_text_view_scroll_mark_onscreen( GTK_TEXT_VIEW(MonitorFramesView), mark ); 

	}

gdk_threads_leave();

	free( TextToFreeAfterUse );
	return FALSE; // add line one time.
}

// g_idle_add() technic call must be used to run on Win32 (called per gtk_main task...)
// gdk_threads_enter() & gdk_threads_leave() in another thread with gtk functions between only working on Linux.
void MonitorWindowAddText( char * text )
{
	char * AllocText = malloc( strlen(text)+1 );
	if ( AllocText )
	{
		strcpy( AllocText, text );
		g_idle_add( MonitorWindowAddTextFromMainGtk, AllocText );
	}
	else
	{
		printf("Failed to alloc mem in %s()\n", __FUNCTION__);
	}

#ifdef BBBBBBBBBBBBBBBBBBB
	GtkTextBuffer *buffer;
	GtkTextIter iter;
	GtkTextMark *mark;

gdk_threads_enter();

	if ( GTK_WIDGET_VISIBLE( GTK_WINDOW(MonitorWindow) ) )
	{
#ifdef AAAAAAAAAAAAAAAA
		/* Get the text buffer */
		buffer = gtk_text_view_get_buffer( GTK_TEXT_VIEW( MonitorFramesView ) );
		/* Get end iter */
		gtk_text_buffer_get_end_iter( buffer, &iter );
		/* Add the message to the text buffer */
		gtk_text_buffer_insert( buffer, &iter, text, -1 );
		/* Scroll to end iter */
		gtk_text_view_scroll_to_iter( GTK_TEXT_VIEW (MonitorFramesView),
									&iter, 0.0, FALSE, 0, 0 );
#endif
		/* How do I make a text view scroll to the end of the buffer automatically ?
		A good way to keep a text buffer scrolled to the end is to place a mark at the end of the buffer, and give it right gravity.
		The gravity has the effect that text inserted at the mark gets inserted before, keeping the mark at the end.
		To ensure that the end of the buffer remains visible, use gtk_text_view_scroll_to_mark() to scroll to the mark after
		inserting new text. */
		
		/* Returns the GtkTextBuffer being displayed by this text view. */
		buffer = gtk_text_view_get_buffer( GTK_TEXT_VIEW(MonitorFramesView) );
		/* Returns the mark that represents the cursor (insertion point). */
		mark = gtk_text_buffer_get_insert( buffer );
		/* Initializes iter with the current position of mark. */
		gtk_text_buffer_get_iter_at_mark( buffer, &iter, mark );
		/* Inserts buffer at position iter. */
		gtk_text_buffer_insert( buffer, &iter, text, -1 );
		/* Scrolls text_view the minimum distance such that mark is contained within the visible area of the widget. */
		if ( gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON( MonitorAutoScroll ) ) )
			gtk_text_view_scroll_mark_onscreen( GTK_TEXT_VIEW(MonitorFramesView), mark ); 
	}

gdk_threads_leave();
#endif
}

